package com.xcity.game.combat.listener.combat;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;

import com.xcity.db.entity.Employee;
import com.xcity.db.entity.Mine;
import com.xcity.db.entity.Player;
import com.xcity.game.combat.Combat;
import com.xcity.game.combat.Combat.State;
import com.xcity.game.combat.Combat.Type;
import com.xcity.game.combat.CombatBuilder;
import com.xcity.game.combat.CombatException;
import com.xcity.game.combat.CombatService;
import com.xcity.game.combat.CombatUtils;
import com.xcity.game.combat.Round;
import com.xcity.game.combat.builder.DefaultCombatBuilder;
import com.xcity.game.combat.listener.CombatListener;
import com.xcity.game.common.Cause;
import com.xcity.game.common.MessageConst;
import com.xcity.game.event.GameEvents;
import com.xcity.game.formation.Formation;
import com.xcity.game.map.MapService;
import com.xcity.game.map.MapUtils;
import com.xcity.game.player.cache.PlayerCacheService;
import com.xcity.game.vip.VipUtils;
import com.xcity.pomelo.push.msg.CombatEndPush;
import com.xcity.pomelo.push.msg.StoneLackPush;
import com.xcity.pomelo.request.CombatInfoRequest;
import com.xcity.pomelo.request.CombatMineAttackRequest;
import com.xcity.pomelo.response.CombatInfoResponse;
import com.xcity.pomelo.response.CombatInfoResponse.Team;
import com.xcity.pomelo.response.CombatInfoResponse.TeamBuilder;
import com.xcity.pomelo.response.CombatResponse;

import naga.x.App;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Packet;
import naga.x.net.Session;
import naga.x.util.TimeUtils;

public class MineAttackCombatListener implements CombatListener {
	
	protected Player source, target;
	protected Mine mine;
	protected static final Logger LOG = CombatService.LOG;
	protected int sourceFightValuel;
//	long[] employees;
	List<Employee> employees;
	
	static class Result{
		public int map;
		public int pos;
		public long ownerId;
		public String name;
		public String icon;
		public int type;
		public int leftSecond;
		public int mineId;
		public List<Long> guards;
		public int mapX;
		public int mapY;
		public Result(Player player, Mine mine){
			this.map = mine.getMap();
			int[] xy = MapUtils.map2mapXY(this.map);
			mapX = xy[0];//this.map % MapService.MAP_X_BLOCKS;
			mapY = xy[1];//this.map / MapService.MAP_X_BLOCKS;
			this.pos = mine.getPos();
			ownerId = player.getId();
			name = player.getName();
			icon = player.getIcon();
			type = mine.getMineType();
			leftSecond = (int) ((mine.getTakeTime() + (mine.getExtendCount()) * MapService.TAKE_MAX_DURATION - TimeUpdater.getInstance().now()) / 1000L);
			if(leftSecond < 0){
				leftSecond = 0;
			}
			mineId = mine.getId();
			guards = player.getMines().getEidList();
		}
	}
	
	@Deprecated //用不上了
	@Override
	public void prepareCombat(Session session, CombatInfoRequest packet) throws CombatException {
		int map = packet.getMap();
		int pos = packet.getPos();
		init(map, pos, new long[]{0, 0, 0, 0});
		long targetId = mine.getOwnerId();//TODO
		if(targetId == 0){
			throw new CombatException(MessageConst.ILLEGAL_OPERATION);
		}
		source = session.getClient();
		target = App.getApp().getServiceManager().get(PlayerCacheService.class).find(targetId);
		if(target == null){
			throw new CombatException(MessageConst.PLAYER_NOT_EXIST);
		}
		validate();
		
		TeamBuilder sourceTeamBuilder = new TeamBuilder();//.setLeader(source);
		long[] srcEmployeeIds = source.getFormations().get(Formation.TYPE_MINE_DEFENSE).getIds();
		for(long eid : srcEmployeeIds){
			sourceTeamBuilder.addEmployeeMember(eid);
		}
		Team sourceTeam = sourceTeamBuilder.build();
		sourceFightValuel = sourceTeam.combatPower;
		
		TeamBuilder targetTeamBuilder = new TeamBuilder();//.setLeader(target);
		long[] tgtEmployeeIds = target.getFormations().get(Formation.TYPE_MINE_DEFENSE).getIds();
		for(long eid : tgtEmployeeIds){
			targetTeamBuilder.addEmployeeMember(eid);
		}
		Team targetTeam = targetTeamBuilder.build();
		
		session.send(new CombatInfoResponse(packet.getSerial(), sourceTeam, targetTeam, Formation.TYPE_MINE_DEFENSE));
	}

	@Override
	public CombatResponse create(CombatService service, Type type, Session session, Packet packet) throws CombatException {
		CombatMineAttackRequest req = (CombatMineAttackRequest) packet;
		int map = req.getMap();
		int pos = req.getPos();
		long[] eids = req.getEids();
		source = session.getClient();
		init(map, pos, eids);
		long targetId = mine.getOwnerId();//TODO
		target = App.getApp().getServiceManager().get(PlayerCacheService.class).find(targetId);
		if(target == null){
			throw new CombatException(MessageConst.PLAYER_NOT_EXIST);
		}
		List<Long> tarIds = target.getMines().tryGetMineMap().get(mine.getId());
		if(tarIds.size() != 4){
			throw new CombatException(MessageConst.MINE_WRONG_EMPLOYEE);
		}
		List<Employee> targetEmployees = new ArrayList<Employee>();
		int emptyCount = 0;
		for(int i = 0; i < tarIds.size(); i++){
			long teid = tarIds.get(i);
			Employee e = teid != 0L ? target.getEmployees().get(teid) : null;
			targetEmployees.add(e);
			if(e == null){
				emptyCount++;
			}
		}
		if(emptyCount >= 4){
			throw new CombatException(MessageConst.MINE_WRONG_EMPLOYEE);
		}

		validate();
		mine.setState(MapService.MINE_STATE_FIGHTING);

//		List<Employee> employees = Arrays.asList(source.getFormations().get(Formation.TYPE_MINE_DEFENSE).getUnits());
		CombatBuilder builder = new DefaultCombatBuilder()
				.setType(type)
				.setListener(this)
//				.setSourceLeader(source)
				.addSourceMembers(employees)
//				.setDestLeader(target)
				.addDestMembers(targetEmployees);//Arrays.asList(target.getFormations().get(Formation.TYPE_MINE_DEFENSE).getUnits())
		
		
//		sourceFightValuel = CombatUtils.calcCombatPower(source);
		for(int i = 0; i < employees.size(); i++){
			if(employees.get(i) != null){
				sourceFightValuel = sourceFightValuel + CombatUtils.calcCombatPower(employees.get(i));
			}
		}
		return new CombatResponse(req.getSerial(), builder.build());
	}

	@Override
	public void end(Combat combat, boolean notify) {
		Result ref = null;
		long endTime = TimeUpdater.getInstance().now();
		CombatEndPush push = new CombatEndPush(Combat.FAIL, Combat.Type.MINE_ATTACK, combat.getId());
		if(combat.getState() == State.SOURCE_WON){
			push.setResult(Combat.SUCC);
			List<Long> eids = new ArrayList<Long>();
			for(int i = 0; i < employees.size(); i++){
				if(employees.get(i) != null){
					eids.add(employees.get(i).getId());
				}else{
					eids.add(0L);
				}
			}
			App.getApp().getServiceManager().get(MapService.class).handleMineBattleEnd(mine, source, target, endTime, true, eids, sourceFightValuel);
			ref = new Result(source, mine);
			push.setRef(ref);
			App.getApp().getEventManager().addEvent(GameEvents.EVENT_MINE_ATTACK_SUCC, source, target, mine);
		}else{
			App.getApp().getServiceManager().get(MapService.class).handleMineBattleEnd(mine, source, target, endTime, false, null, 0);
		}
		if (notify) {
			source.send(push);
		}
		mine.setState(MapService.MINE_STATE_NONE);
		LOG.info("[MINEATTACK]SRC[{}]TGT[{}]MAP[{}]POS[{}]RESULT[{}]", source.getId(), target.getId(), mine.getMap(), mine.getPos(), push.getResult());
	}
	
	public void init(int map, int pos, long[] eids) throws CombatException{
		mine = App.getApp().getServiceManager().get(MapService.class).findMineByMapPos(map, pos);
		if(mine == null){
			throw new CombatException(MessageConst.MINE_NOT_EXIST);
		}
		if(eids == null || eids.length != 4){
			throw new CombatException(MessageConst.MINE_WRONG_EMPLOYEE);
		}
		employees = new ArrayList<Employee>();
		int emptyCount = 0;
		for(long eid : eids){
			Employee e = eid != 0L ? source.getEmployees().get(eid) : null;
			employees.add(e);
			if(e == null){
				emptyCount++;
			}
		}
		if(emptyCount >= 4){
			throw new CombatException(MessageConst.MINE_MUST_HAVE_EMPLOYEE);
		}
	}
	
	public void validate() throws CombatException{
		if(source.getMines().mineTakenCount() >= VipUtils.getTemplate(source.getVipLvl()).getMineTakeLimit()){
//			throw new CombatException(MessageConst.MINE_TAKE_LIMIT);
		}
		if(source.getId() == target.getId()){
			throw new CombatException(MessageConst.MINE_TAKE_SELF);
		}
		if(source.getLevel() < MapService.SHOW_MAP_LEVEL){
			throw new CombatException(MessageFormat.format(MessageConst.MINE_LEVEL_LIMIT, MapService.SHOW_MAP_LEVEL) );
		}
		//TODO
		if(source.getMines().mineTaken(mine.getId())){
			throw new CombatException(MessageConst.MINE_TAKEN);
		}
		long time = TimeUpdater.getInstance().now();
		long start = TimeUtils.getTodayTimeMillis(time, MapService.MINE_TAKE_TIME_LIMIT_START, 0);
		long end = TimeUtils.getTodayTimeMillis(time, MapService.MINE_TAKE_TIME_LIMIT_END, 0);
		if(time > start && time < end){
			throw new CombatException(MessageFormat.format(MessageConst.MINE_TIME_LIMIT, MapService.MINE_TAKE_TIME_LIMIT_START, MapService.MINE_TAKE_TIME_LIMIT_END));
		}
		if(mine.getTypeTemp().getCostStone() > 0 && source.getStone() < mine.getTypeTemp().getCostStone()){
			source.send(StoneLackPush.DEFAULT);
			throw new CombatException(MessageConst.MINE_NO_STONE);
		}
		if(mine.getTypeTemp().getCostStr() > 0 && source.getStrength() < mine.getTypeTemp().getCostStr()){
			throw new CombatException(MessageConst.MINE_NO_STR);
		}
		if(mine.getState() != MapService.MINE_STATE_NONE){
			throw new CombatException(MessageConst.MINE_FIGHTING);
		}
		if(mine.getTypeTemp().getCostStone() > 0 && !source.costStone(mine.getTypeTemp().getCostStone(), Cause.MINE_TAKE)){
			throw new CombatException(MessageConst.MINE_NO_STONE);
		}
		if(mine.getTypeTemp().getCostStr() > 0 && !source.decStrength(mine.getTypeTemp().getCostStr(), Cause.MINE_TAKE)){
			throw new CombatException(MessageConst.MINE_NO_STR);
		}
	}

	@Override
	public void roundStart(Round round) {
	}

	@Override
	public void roundEnd(Round round) {
	}
}
